#include<bits/stdc++.h>
using namespace std;
typedef long long LL;


int T;

struct Car{
    int d,v,a;
};

const int N = 1e5 + 5;

inline int Pow2(int x){
    return x * x;
}

//Vars,remember to clear them every round

int n,m,L,V;
Car carsInc[N];int cntI;
Car carsDec[N];int cntD;
Car carsAve[N];int cntA;
int MonitorPos[N];

int LMonitorToBlockAve[N];// The leftest montor to block a average-speed car

int LMonitorToBlockDec[N];// The leftest montor to block a Decresing-speed car

int RMonitorToBlockDec[N];// The rightest montor to block a Decresing-speed car
int LMonitorToBlockInc[N];// The leftest montor to block a Incresing-speed car

bool NeedToChkInc[N];
bool NeedToChkDec[N];
bool NeedToChkAve[N];

bool OnlyHasInc = false;
bool OnlyHasDec = false;
bool OnlyHasAve = false;
//

int FindNearestMonitorId(int p){
    return upper_bound(MonitorPos + 1,MonitorPos + m + 1,p - 1) - MonitorPos;
}
int FindNearestMonitorDis(int id,int p){
    return MonitorPos[id] - p;
}

float GetCarSpeedAtPos(int d,int v,int a,int p){
    float Distance = p - d;
    return sqrt(Pow2(v) + 2 * a * Distance);
}

//We need to find the position when the car's speed equals to V;
//Then,Find the nearest Monitor left of it.
int GetFurthestMonitorToBlockDecCar(Car car){
    //First Step

    int DeltaV = car.v - V;
    float TimeToDec = float(DeltaV) / abs(car.a);
    float DistanceToGo = car.v * TimeToDec + 0.5 * car.a * Pow2(TimeToDec);
    int TargetPos = DistanceToGo + car.d;//Does not need to SiSheWuRu

    //Second Step
    if(TargetPos >= L) return m;  
    int Id = lower_bound(MonitorPos + 1,MonitorPos + m + 1,TargetPos + 1) - MonitorPos;
    return Id;
}

int main(){
#ifndef DEBUG
#ifndef DEBUGIO
    freopen("detect.in","r",stdin);
    freopen("detect.out","w",stdout);
#endif
#endif
#ifdef DEBUGIO
    freopen("InputFile","r",stdin);
    freopen("OutputFile","w",stdout);
#endif

    scanf("%d",&T);
    while(T--){
        cntI = 0;cntD = 0;cntA = 0;
        OnlyHasAve = OnlyHasDec = OnlyHasInc = true;

        scanf("%d %d %d %d",&n,&m,&L,&V);
        for(int i = 1;i <= n;i++){
            int _d,_a,_v;
            scanf("%d %d %d",&_d,&_v,&_a);
            if(_a > 0){
                if(GetCarSpeedAtPos(_d,_v,_a,L) <= V){
                    continue;
                }
                carsInc[++cntI] = {_d,_v,_a};
            }
            else if(_a < 0){
                if(_v <= V){
                    continue;
                }
                carsDec[++cntD] = {_d,_v,_a};
            }
            else{
                if(_v <= V){
                    continue;
                } 
                carsAve[++cntA] = {_d,_v,_a};
            }
        }
        for(int i = 1;i <= m;i++){
            scanf("%d",&MonitorPos[i]);
        }
        sort(MonitorPos + 1,MonitorPos + m + 1);
        
        //Question 1
        int countOverSpeed = 0;

        int FurthestMonitorPos = MonitorPos[m];
        for(int i = 1;i <= cntI;i++){
            Car cur = carsInc[i];
            float Distance = FurthestMonitorPos - cur.d;
            float MomentSpeed = sqrt(Pow2(cur.v) + 2 * cur.a * Distance);
            if(MomentSpeed > V){
                ++countOverSpeed;
                NeedToChkInc[i] = true;

                OnlyHasAve = OnlyHasDec = false;
#ifdef DEBUG
                cerr << cur.d << ' ' << cur.v << ' ' << cur.a << "+\n";
#endif
            
           }
        }

        for(int i = 1;i <= cntD;i++){
            Car cur = carsDec[i];
            int Id = FindNearestMonitorId(cur.d);
            float Distance = FindNearestMonitorDis(Id,cur.d);
            float MomentSpeed = sqrt(Pow2(cur.v) + 2 * cur.a * Distance);

#ifdef DEBUG
            cerr << " !" << Id << "! \n";
#endif

            LMonitorToBlockDec[i] = Id;// For Question 2
            if(MomentSpeed > V){
                ++countOverSpeed;
                NeedToChkDec[i] = true;

                OnlyHasInc = OnlyHasAve = false;
#ifdef DEBUG
                cerr << cur.d << ' ' << cur.v << ' ' << cur.a << "+\n";
#endif
            }
        }

        //if this type of car is in the array,its v is bigger to V
        for(int i = 1;i <= cntA;i++){
            Car cur = carsAve[i];
            if(cur.d <= FurthestMonitorPos){
                ++countOverSpeed;
                NeedToChkAve[i] = true;

                OnlyHasInc = OnlyHasDec = false;
#ifdef DEBUG
                cerr << cur.d << ' ' << cur.v << ' ' << cur.a << "+\n";
#endif
            }
        }

        //END OF QUESTION 1
        //Question 2

        int MaxCloses = 0;
        //Calc LMonitorToBlockInc
        for(int i = 1;i <= cntI;i++){
            Car cur = carsInc[i];
            int Id = FindNearestMonitorId(cur.d);
            LMonitorToBlockInc[i] = Id;
        }

        //Calc RMonitorToBlockDec
        for(int i = 1;i <= cntD;i++){
            Car cur = carsDec[i];
            RMonitorToBlockDec[i] = GetFurthestMonitorToBlockDecCar(cur);
        }

        //Calc LMonitorToBlockAve
        for(int i = 1;i <= cntA;i++){
            Car cur = carsAve[i];
            int Id = FindNearestMonitorId(cur.d);
            LMonitorToBlockAve[i] = Id;
        }

        if(countOverSpeed <= 0){
            printf("%d %d\n",countOverSpeed,m);
            continue;
        }
        if(OnlyHasInc){
            MaxCloses = m - 1;
        }
        else if(OnlyHasDec){
            int Closes = 0;

            int Numbers[N];bool IsUsed[N];
            bool SegmentIsIn[N];int NSeg = 0;
            memset(SegmentIsIn,false,sizeof(SegmentIsIn));
            memset(IsUsed,false,sizeof(IsUsed));
            for(int i = 1;i <= m;i++)   Numbers[i] = 0;
            for(int i = 1;i <= cntD;i++){
                if(NeedToChkDec[i]){
                    ++NSeg;
                    Numbers[LMonitorToBlockDec[i]]++;
                    Numbers[RMonitorToBlockDec[i]]--;
                    SegmentIsIn[i] = true;
                }
            }

            for(int i = 1;i <= m;i++){
                Numbers[i] += Numbers[i - 1];
            }

            while(NSeg > 0){
                int maxN = -1,maxP;
                for(int i = 1;i <= m;i++){
                    if(Numbers[i] >= maxN && (!IsUsed[i])){
                        maxN = Numbers[i];
                        maxP = i;
                    }
                }
                IsUsed[maxP] = true;
                for(int i = 1;i <= cntD;i++){
                    if(NeedToChkDec[i] && LMonitorToBlockDec[i] <= maxP && RMonitorToBlockDec[i] >= maxP){
                        NSeg--;
                        SegmentIsIn[i] = false;
                    }
                }

                for(int i = 1;i <= m;i++)   Numbers[i] = 0;
                for(int i = 1;i <= cntD;i++){
                    if(SegmentIsIn[i] && NeedToChkDec[i]){
                        Numbers[LMonitorToBlockDec[i]]++;
                        Numbers[RMonitorToBlockDec[i]]--;
                    }
                }

                for(int i = 1;i <= m;i++){
                    Numbers[i] += Numbers[i - 1];
                }

                ++Closes;
            }

            MaxCloses = m - Closes;
        }
        else if(OnlyHasAve){
            MaxCloses = m - 1;
        }
        else{
            int LSeg[N],RSeg[N],SegN = 0;
            for(int i = 1;i <= cntI;i++){
                if(!NeedToChkInc[i]) continue;
                ++SegN;
                LSeg[SegN] = LMonitorToBlockInc[i];
                RSeg[SegN] = m;
            }
            for(int i = 1;i <= cntD;i++){
                 if(!NeedToChkDec[i]) continue;
                ++SegN;
                LSeg[SegN] = LMonitorToBlockDec[i];
                RSeg[SegN] = RMonitorToBlockDec[i];
            }
            for(int i = 1;i <= cntA;i++){
                 if(!NeedToChkAve[i]) continue;
                ++SegN;
                LSeg[SegN] = LMonitorToBlockAve[i];
                RSeg[SegN] = m;
            }

            int Closes = 0;

            int Numbers[N];
            bool SegmentIsIn[N];int NSeg = m;
            memset(SegmentIsIn,true,sizeof(SegmentIsIn));
            for(int i = 1;i <= m;i++)   Numbers[i] = 0;
            for(int i = 1;i <= cntD;i++){
                Numbers[LSeg[i]]++;
                Numbers[RSeg[i]]--;
            }

            for(int i = 1;i <= m;i++){
                Numbers[i] += Numbers[i - 1];
            }

            while(NSeg > 0){
                int maxN = -1,maxP;
                for(int i = 1;i <= m;i++){
                    if(Numbers[i] >= maxN){
                        maxN = Numbers[i];
                        maxP = i;
                    }
                }
                for(int i = 1;i <= cntD;i++){
                    if(LSeg[i] <= maxP && RSeg[i] >= maxP){
                        NSeg--;
                        SegmentIsIn[i] = false;
                    }
                }
                for(int i = 1;i <= m;i++)   Numbers[i] = 0;
                for(int i = 1;i <= cntD;i++){
                    if(SegmentIsIn[i]){
                        Numbers[LSeg[i]]++;
                        Numbers[RSeg[i]]--;
                    }
                }

                for(int i = 1;i <= m;i++){
                    Numbers[i] += Numbers[i - 1];
                }

                ++Closes;
            }

            MaxCloses = m - Closes;
        }
        
        //END OF QUESTION 2

        printf("%d %d\n",countOverSpeed,MaxCloses);
    }
    return 0;
}
